﻿// <copyright file="GameClock.xaml.cs" company="ALCPU">
// Copyright (c) 2010 All Right Reserved
// </copyright>
// <author>Arthur Liberman</author>
// <email>Arthur_Liberman@hotmail.com</email>
// <date>04-05-2010</date>
// <summary>Contains the GameClock codebehind.</summary>

namespace Chess
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Timers;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Windows.Threading;
    using ChessDefinitions;

    /// <summary>
    /// Interaction logic for GameClock.xaml
    /// </summary>
    public partial class GameClock : UserControl
    {
        /// <summary>
        /// The clock timer.
        /// </summary>
        private DispatcherTimer timer;

        /// <summary>
        /// The time on Clock1
        /// </summary>
        private TimeSpan time1;

        /// <summary>
        /// The time on Clock2
        /// </summary>
        private TimeSpan time2;

        /// <summary>
        /// The time limit when in Timer Mode.
        /// </summary>
        private TimeSpan timeLimit;

        /// <summary>
        /// The current clock mode.
        /// </summary>
        private ClockMode clockMode;

        /// <summary>
        /// The color of the current player.
        /// </summary>
        private IPieceColor currentColor;

        /// <summary>
        /// <c>true</c> is active, <c>false</c> otherwise.
        /// </summary>
        private bool isClockActive;

        /// <summary>
        /// Initializes a new instance of the <see cref="GameClock"/> class.
        /// </summary>
        public GameClock()
        {
            this.InitializeComponent();

            this.ClockMode = ClockMode.Stopwatch;
            this.ResetClock();

            this.timer = new DispatcherTimer(new TimeSpan(0, 0, 0, 1, 0), DispatcherPriority.Loaded, new EventHandler(this.Timer_Elapsed), this.Dispatcher);
            this.timer.Stop();
        }

        /// <summary>
        /// Occurs when the clock times out.
        /// </summary>
        public event EventHandler TimeoutOccured;

        /// <summary>
        /// Gets or sets the clock mode.
        /// </summary>
        /// <value>The clock mode.</value>
        public ClockMode ClockMode
        {
            get
            {
                return this.clockMode;
            }

            set
            {
                if (!this.isClockActive)
                {
                    this.clockMode = value;
                    this.clock1.ClockMode = value;
                    this.clock2.ClockMode = value;
                }
            }
        }

        /// <summary>
        /// Gets or sets the time limit.
        /// </summary>
        /// <value>The time limit.</value>
        public TimeSpan TimeLimit
        {
            get { return this.timeLimit; }
            set { this.SetTimeLimit(value); }
        }

        /// <summary>
        /// Gets the current player.
        /// </summary>
        /// <value>The current player.</value>
        public IPieceColor CurrentPlayer
        {
            get { return this.currentColor; }
        }

        /// <summary>
        /// Gets or sets the move count.
        /// </summary>
        /// <value>The move count.</value>
        public MoveCounter MoveCount
        {
            get
            {
                if (this.currentColor == IPieceColor.White)
                {
                    return this.moveCounter1;
                }
                else
                {
                    return this.moveCounter2;
                }
            }

            set
            {
                if (this.currentColor == IPieceColor.White)
                {
                    this.moveCounter1 = value;
                }
                else
                {
                    this.moveCounter2 = value;
                }
            }
        }

        /// <summary>
        /// Toggles the player.
        /// </summary>
        public void TogglePlayer()
        {
            if (this.currentColor == IPieceColor.White)
            {
                this.currentColor = IPieceColor.Black;
                if (this.isClockActive)
                {
                    this.led1.TurnOff();
                    if (this.clockMode == ClockMode.Timer && this.time2 < TimeSpan.FromMinutes(1))
                    {
                        this.led2.Flash();
                    }
                    else
                    {
                        this.led2.TurnOn();
                    }
                }
            }
            else
            {
                this.currentColor = IPieceColor.White;
                if (this.isClockActive)
                {
                    this.led2.TurnOff();
                    if (this.clockMode == ClockMode.Timer && this.time1 < TimeSpan.FromMinutes(1))
                    {
                        this.led1.Flash();
                    }
                    else
                    {
                        this.led1.TurnOn();
                    }
                }
            }
        }

        /// <summary>
        /// Sets the time limit.
        /// </summary>
        /// <param name="timeLimit">The time limit.</param>
        public void SetTimeLimit(TimeSpan timeLimit)
        {
            if (!this.isClockActive)
            {
                this.timeLimit = timeLimit;
                if (this.ClockMode == ClockMode.Stopwatch)
                {
                    this.time1 = new TimeSpan();
                    this.time2 = new TimeSpan();
                    this.clock1.Time = new TimeSpan();
                    this.clock2.Time = new TimeSpan();
                }
                else if (this.ClockMode == ClockMode.Timer)
                {
                    this.time1 = timeLimit;
                    this.time2 = timeLimit;
                    this.clock1.Time = timeLimit;
                    this.clock2.Time = timeLimit;
                }
            }
        }

        /// <summary>
        /// Resets the clock.
        /// </summary>
        public void ResetClock()
        {
            if (!this.isClockActive)
            {
                this.SetTimeLimit(this.time1);
                this.led1.TurnOff();
                this.led2.TurnOff();
                this.currentColor = IPieceColor.White;
                this.flag1.Fill = (Brush)App.Current.FindResource("RedFlagDown");
                this.flag2.Fill = (Brush)App.Current.FindResource("RedFlagDown");
                this.moveCounter1.ResetCounter();
                this.moveCounter2.ResetCounter();
            }
        }

        /// <summary>
        /// Starts the clock.
        /// </summary>
        public void StartClock()
        {
            this.timer.Start();
            this.isClockActive = true;
            this.UpdateClock(IPieceColor.White);
            this.UpdateClock(IPieceColor.Black);
        }

        /// <summary>
        /// Stops the clock.
        /// </summary>
        public void StopClock()
        {
            this.timer.Stop();
            this.isClockActive = false;
            this.led1.TurnOff();
            this.led2.TurnOff();
        }

        /// <summary>
        /// Updates the clock.
        /// </summary>
        /// <param name="pieceColor">Color of the piece.</param>
        private void UpdateClock(IPieceColor pieceColor)
        {
            if (this.isClockActive)
            {
                if (this.ClockMode == ClockMode.Stopwatch)
                {
                    if (pieceColor == IPieceColor.White)
                    {
                        this.clock1.Time = this.time1;
                    }
                    else
                    {
                        this.clock2.Time = this.time2;
                    }
                }
                else if (this.ClockMode == ClockMode.Timer)
                {
                    if (pieceColor == IPieceColor.White)
                    {
                        this.clock1.Time = this.timeLimit.Subtract(this.time1);
                        if (this.time1 == TimeSpan.FromTicks(0))
                        {
                            this.HandleTimeout();
                        }
                        else if (this.currentColor == pieceColor)
                        {
                            if (this.time1 < TimeSpan.FromMinutes(1) && !this.led1.Flashing)
                            {
                                this.led1.Flash();
                            }
                            else if (this.time1 >= TimeSpan.FromMinutes(1))
                            {
                                this.led1.TurnOn();
                            }
                        }
                    }
                    else
                    {
                        this.clock2.Time = this.timeLimit.Subtract(this.time2);
                        if (this.time2 == TimeSpan.FromTicks(0))
                        {
                            this.HandleTimeout();
                        }
                        else if (this.currentColor == pieceColor)
                        {
                            if (this.time2 < TimeSpan.FromMinutes(1) && !this.led2.Flashing)
                            {
                                this.led2.Flash();
                            }
                            else if (this.time2 >= TimeSpan.FromMinutes(1))
                            {
                                this.led2.TurnOn();
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Handles the timeout event.
        /// </summary>
        private void HandleTimeout()
        {
            this.StopClock();
            if (this.currentColor == IPieceColor.White)
            {
                this.flag1.Fill = (Brush)App.Current.FindResource("RedFlagUp");
            }
            else
            {
                this.flag2.Fill = (Brush)App.Current.FindResource("RedFlagUp");
            }

            if (this.TimeoutOccured != null)
            {
                EventArgs args = new EventArgs();
                foreach (EventHandler handler in this.TimeoutOccured.GetInvocationList())
                {
                    try
                    {
                        handler.Invoke(this, args);
                    }
                    catch (Exception)
                    { 
                    }
                }
            }
        }

        /// <summary>
        /// Handles the Elapsed event of the timer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void Timer_Elapsed(object sender, EventArgs e)
        {
            if (this.isClockActive)
            {
                if (this.ClockMode == ClockMode.Stopwatch)
                {
                    if (this.currentColor == IPieceColor.White)
                    {
                        this.time1 = this.time1.Add(TimeSpan.FromSeconds(1));
                    }
                    else
                    {
                        this.time2 = this.time2.Add(TimeSpan.FromSeconds(1));
                    }
                }
                else if (this.ClockMode == ClockMode.Timer)
                {
                    if (this.currentColor == IPieceColor.White)
                    {
                        this.time1 = this.time1.Subtract(TimeSpan.FromSeconds(1));
                    }
                    else
                    {
                        this.time2 = this.time2.Subtract(TimeSpan.FromSeconds(1));
                    }
                }

                this.UpdateClock(this.currentColor);
            }
        }
    }
}
